package com.yc.boot.sys.business;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeNode;
import cn.hutool.core.lang.tree.TreeNodeConfig;
import cn.hutool.core.lang.tree.TreeUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yc.boot.common.model.response.Outcome;
import com.yc.boot.sys.entity.SysMenu;
import com.yc.boot.sys.entity.SysRoleMenu;
import com.yc.boot.sys.service.SysMenuService;
import com.yc.boot.sys.service.SysRoleMenuService;
import com.yc.boot.sys.model.UserInfo;
import com.yc.boot.sys.model.find.FindMenuPage;
import com.yc.boot.sys.model.find.FindMenuTree;
import com.yc.boot.sys.model.save.SaveMenu;
import com.yc.boot.sys.model.update.ResetRoleMenu;
import com.yc.boot.sys.model.update.UpdateMenu;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

import static com.yc.boot.common.constant.BaseConstant.*;


/**
 * @author 杨智杰
 * @since 2021/8/18 13:15
 */
@Service
public class SysMenuBusiness {

    @Resource
    private SysMenuService sysMenuService;

    @Resource
    private SysUserBusiness sysUserBusiness;

    @Resource
    private SysRoleMenuService sysRoleMenuService;

    /**
     * 获取当前登录用户可以使用的菜单栏
     *
     * @param param 查询参数
     * @return 菜单树
     */
    public List<Tree<String>> getMenuTree(FindMenuTree param) {
        if (param.getIsAll()) {
            return listToTree(sysMenuService.list());
        }
        if (ObjectUtil.isNotNull(param.getRoleId())) {
            List<SysRoleMenu> roleMenuList = sysRoleMenuService.list(new QueryWrapper<SysRoleMenu>()
                    .lambda().eq(SysRoleMenu::getRoleId, param.getRoleId()));
            if (CollUtil.isNotEmpty(roleMenuList)) {
                return listToTree(sysMenuService.list(new QueryWrapper<SysMenu>()
                        .lambda().in(SysMenu::getId, roleMenuList.stream()
                                .map(SysRoleMenu::getMenuId).collect(Collectors.toSet()))));
            }
        }
        if (param.getIsLogin()) {
            UserInfo userInfo = sysUserBusiness.getUserInfo();
            if (CollUtil.isNotEmpty(userInfo.getAuthStrList())) {
                if (userInfo.getAuthStrList().stream().anyMatch(ADMIN::equals)) {
                    return listToTree(sysMenuService.list(new QueryWrapper<SysMenu>().lambda()
                            .eq(SysMenu::getStatus, ONE).orderByAsc(SysMenu::getSort)));
                }
                return listToTree(sysMenuService.list(new QueryWrapper<SysMenu>().lambda()
                        .in(CollUtil.isNotEmpty(userInfo.getAuthStrList()), SysMenu::getAuthStr, userInfo.getAuthStrList())
                        .eq(SysMenu::getStatus, ONE).orderByAsc(SysMenu::getSort)));
            }
        }
        return null;
    }

    /**
     * 查询
     *
     * @param param 查询条件
     * @return 查询结果
     */
    public IPage<SysMenu> page(FindMenuPage param) {
        List<SysRoleMenu> sysRoleMenuList = new ArrayList<>();
        if (ObjectUtil.isNotNull(param.getRoleId())) {
            sysRoleMenuList = sysRoleMenuService.list(new QueryWrapper<SysRoleMenu>().lambda().eq(SysRoleMenu::getRoleId, param.getRoleId()));
            if (CollUtil.isEmpty(sysRoleMenuList)) {
                sysRoleMenuList.add(new SysRoleMenu().setMenuId(-99L));
            }
        }
        return sysMenuService.page(new Page<>(param.getCurrent(), param.getSize()),
                new QueryWrapper<SysMenu>().lambda()
                        .eq(ObjectUtil.isNotNull(param.getId()), SysMenu::getId, param.getId())
                        .eq(ObjectUtil.isNotNull(param.getType()), SysMenu::getType, param.getType())
                        .like(StrUtil.isNotBlank(param.getName()), SysMenu::getName, param.getName())
                        .eq(ObjectUtil.isNotNull(param.getStatue()), SysMenu::getStatus, param.getStatue())
                        .like(StrUtil.isNotBlank(param.getAuthStr()), SysMenu::getAuthStr, param.getAuthStr())
                        .in(CollUtil.isNotEmpty(sysRoleMenuList), SysMenu::getId, sysRoleMenuList.stream()
                                .map(SysRoleMenu::getMenuId).collect(Collectors.toSet()))
                        .orderByAsc(SysMenu::getSort));
    }

    /**
     * 新增
     *
     * @param param 新增数据
     * @return 是否成功
     */
    public Outcome save(SaveMenu param) {
        UserInfo userInfo = sysUserBusiness.getUserInfo();
        SysMenu sysMenu = Convert.convert(SysMenu.class, param);
        sysMenu.setCreateBy(userInfo.getId());
        if (sysMenuService.count(new QueryWrapper<SysMenu>().lambda().eq(SysMenu::getAuthStr, sysMenu.getAuthStr())) > ZERO) {
            return Outcome.failure("权限重复!");
        }
        if (sysMenuService.count(new QueryWrapper<SysMenu>().lambda().eq(SysMenu::getName, sysMenu.getName())) > ZERO) {
            return Outcome.failure("菜单重复!");
        }
        return Outcome.status(sysMenuService.save(sysMenu));
    }

    /**
     * 修改
     *
     * @param param 修改数据
     * @return 是否成功
     */
    public Outcome update(UpdateMenu param) {
        UserInfo userInfo = sysUserBusiness.getUserInfo();
        SysMenu sysMenu = Convert.convert(SysMenu.class, param);
        sysMenu.setUpdateBy(userInfo.getId());
        if (StrUtil.isNotBlank(sysMenu.getAuthStr()) &&
                sysMenuService.count(new QueryWrapper<SysMenu>().lambda()
                        .eq(SysMenu::getAuthStr, sysMenu.getAuthStr())
                        .ne(SysMenu::getId, param.getId())) > ZERO) {
            return Outcome.failure("权限重复!");
        }
        if (StrUtil.isNotBlank(sysMenu.getName()) &&
                sysMenuService.count(new QueryWrapper<SysMenu>().lambda()
                        .eq(SysMenu::getName, sysMenu.getName())
                        .ne(SysMenu::getId, param.getId())) > ZERO) {
            return Outcome.failure("菜单重复!");
        }
        return Outcome.status(sysMenuService.updateById(sysMenu));
    }

    /**
     * 删除
     *
     * @param id 根据Id删除
     * @return 是否成功
     */
    @Transactional(rollbackFor = Exception.class)
    public Boolean delete(List<Long> id) {
        UserInfo userInfo = sysUserBusiness.getUserInfo();
        boolean updateBatchById = sysMenuService.updateBatchById(Convert.toList(SysMenu.class, id.stream()
                .map(i -> new SysMenu().setUpdateBy(userInfo.getId()).setId(i)).collect(Collectors.toList())));
        boolean removeByIds = sysMenuService.removeByIds(id);
        return updateBatchById && removeByIds;
    }

    /**
     * 重置角色菜单列表
     *
     * @param param 角色菜单关联
     * @return 是否成功
     */
    @Transactional(rollbackFor = Exception.class)
    public Outcome reset(ResetRoleMenu param) {
        sysRoleMenuService.remove(new QueryWrapper<SysRoleMenu>().lambda()
                .eq(SysRoleMenu::getRoleId, param.getRoleId()));
        sysRoleMenuService.saveBatch(param.getMenuIds().stream().map(id -> new SysRoleMenu()
                .setRoleId(param.getRoleId()).setMenuId(id)).collect(Collectors.toList()));
        return Outcome.success();
    }

    /**
     * 路由地址
     */
    private static final String PATH = "path";

    /**
     * 图标
     */
    private static final String ICON = "icon";

    /**
     * 类型
     */
    private static final String TYPE = "type";

    /**
     * 权限字符
     */
    private static final String AUTH_STR = "authStr";

    /**
     * 是否隐藏
     */
    private static final String IS_HIDE = "isHide";

    /**
     * 状态
     */
    private static final String STATUS = "status";

    /**
     * 外链
     */
    private static final String LINK = "link";

    /**
     * 集合转树
     *
     * @param param
     * @return
     */
///参数对应着数据库里面的一整张表 这张表被转化为一个树结构，表里面的一个一条数据就对应着一个节点。
    private List<Tree<String>> listToTree(List<SysMenu> param) {
        if (CollUtil.isEmpty(param)) {
            return null;
        }
        List<TreeNode<String>> nodeList = CollUtil.newArrayList();
        for (SysMenu sm : param) {
            Map<String, Object> map = new LinkedHashMap<>();
            map.put(PATH, sm.getPath());
            map.put(ICON, sm.getIcon());
            map.put(TYPE, sm.getType());
            map.put(AUTH_STR, sm.getAuthStr());
            map.put(IS_HIDE, sm.getIsHide());
            map.put(STATUS, sm.getStatus());
            map.put(LINK, sm.getLink());
            nodeList.add(new TreeNode<String>().setId(sm.getId().toString()).setParentId(sm.getPid().toString())
                    .setWeight(sm.getSort()).setName(sm.getName()).setExtra(map));
        }
        return TreeUtil.build(nodeList, param.stream().min(Comparator.comparing(SysMenu::getPid)).get().getPid().toString(),
                new TreeNodeConfig().setIdKey("id").setNameKey("name").setWeightKey("sort")
                        .setParentIdKey("pid").setChildrenKey("children"),
                (treeNode, tree) -> {
                    tree.setId(treeNode.getId());
                    tree.setParentId(treeNode.getParentId());
                    tree.setWeight(treeNode.getWeight());
                    tree.setName(treeNode.getName());
                    tree.putExtra(PATH, treeNode.getExtra().get(PATH));
                    tree.putExtra(ICON, treeNode.getExtra().get(ICON));
                    tree.putExtra(TYPE, treeNode.getExtra().get(TYPE));
                    tree.putExtra(AUTH_STR, treeNode.getExtra().get(AUTH_STR));
                    tree.putExtra(IS_HIDE, treeNode.getExtra().get(IS_HIDE));
                    tree.putExtra(STATUS, treeNode.getExtra().get(STATUS));
                    tree.putExtra(LINK, treeNode.getExtra().get(LINK));
                });
    }
}
